package plantshop.view.listeners;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.event.MouseInputListener;
import javax.swing.filechooser.FileFilter;

import plantshop.controller.moves.CustomerBuyRequestMove;
import plantshop.controller.moves.DeleteCreatureMove;
import plantshop.controller.moves.DeletePlantMove;
import plantshop.controller.moves.PlantBuyMove;
import plantshop.controller.moves.PlantDragMove;
import plantshop.model.Customer;
import plantshop.model.Display;
import plantshop.model.Game;
import plantshop.model.Location;
import plantshop.model.Store;
import plantshop.model.exceptions.ImproperFileTypeException;
import plantshop.model.plants.Aster;
import plantshop.model.plants.BurningBush;
import plantshop.model.plants.CommonMilkweed;
import plantshop.model.plants.EasternRedCedar;
import plantshop.model.plants.EnglishIvy;
import plantshop.model.plants.JapaneseBarberry;
import plantshop.model.plants.NorwayMaple;
import plantshop.model.plants.Plant;
import plantshop.model.plants.SweetPepperbush;
import plantshop.model.plants.WhiteOak;
import plantshop.view.View;

public class StoreMouseListener implements MouseInputListener, Serializable{
	private static final long serialVersionUID = 2565463300413896253L;
	private Display startDisplay;
	private int startIndex;
	private Plant plantBeingDragged;
	private static View view;
	private State state;
	private Location oldLoc;
	
	
	
	private int dispEnd;
	private int endIndex;
	
	enum State{
		NORMAL,
		CLICK,
		DRAG,
		SEEDMENU
	}

	public StoreMouseListener(){
	}
	
	public static void setView(View view)
	{
		StoreMouseListener.view = view;
	}

	@Override
	public void mouseClicked(MouseEvent e) {

	}

	@Override
	public void mouseEntered(MouseEvent e) {
		// I don't think we want anything  to happen in this method

	}

	@Override
	public void mouseExited(MouseEvent e) {
		// I don't think we want anything  to happen in this method

	}

	@Override
	public void mousePressed(MouseEvent e) {
		startDisplay = findPlot(e.getPoint());
		if(startDisplay != null){
			startIndex = findLocationInPlot(e.getPoint());
			if(startDisplay.getPlant(startIndex) != null && startDisplay.getPlant(startIndex).isGrown() && (!startDisplay.getPlant(startIndex).getTakenOver())){
				plantBeingDragged = startDisplay.getPlant(startIndex);
			}
			if(plantBeingDragged != null)
				oldLoc = plantBeingDragged.getLoc().clone();
		}
	}

	@Override
	public void mouseReleased(MouseEvent e) {
		if(state != State.SEEDMENU){
			Display endDisplay = findPlot(e.getPoint());
			Customer customer = findCustomer(e.getPoint());
			if(plantBeingDragged != null && trash(e.getPoint())){
				if(plantBeingDragged.getName()=="Common Milkweed"){
					view.queueMove(new DeleteCreatureMove(1));
				}
				if(plantBeingDragged.getName()=="Aster"){
					view.queueMove(new DeleteCreatureMove(1));
				}
				if(plantBeingDragged.getName()=="Eastern Red Cedar"){
					view.queueMove(new DeleteCreatureMove(2));
				}
				boolean whereStart=false;
				int dispStart=-1;
				
				int i = 0;
				
				for(Display d:view.getGame().getStore().getFront()){
					if(startDisplay == d){
						whereStart = true;
						dispStart = i;
					}
					i++;	
				}
				
				i =0;
				for(Display d:view.getGame().getStore().getBack()){
					if(startDisplay == d){
						whereStart = false;
						dispStart = i;
					}
					i++;	
				}
				
				
				 view.queueMove(new DeletePlantMove(whereStart,dispStart,startIndex));
			}
			if(endDisplay == null && plantBeingDragged != null && customer == null){
				plantBeingDragged.setLoc(oldLoc.getX(), oldLoc.getY());
				view.repaint();
			}
			else if(endDisplay != null){
				int endIndex = findLocationInPlot(e.getPoint());
				boolean whereStart=false, whereEnd=false;
				int dispStart=-1, dispEnd=-1;

				int i = 0;
				for(Display d:view.getGame().getStore().getFront()){
					if(startDisplay == d){
						whereStart = true;
						dispStart = i;
					}
					if(endDisplay == d){
						whereEnd = true;
						dispEnd = i;
					}
					i++;	
				}

				i = 0;
				for(Display d:view.getGame().getStore().getBack()){
					if(startDisplay == d){
						whereStart = false;
						dispStart = i;
					}
					if(endDisplay == d){
						whereEnd = false;
						dispEnd = i;
					}
					i++;	
				}
				if((startDisplay != endDisplay || startIndex != endIndex) && plantBeingDragged != null && endDisplay.getPlant(endIndex) == null)
				{
					view.queueMove(new PlantDragMove(whereStart, dispStart, startIndex, whereEnd, dispEnd, endIndex));
				
					if(plantBeingDragged.getName()=="Common Milkweed"){
						view.queueMove(new DeleteCreatureMove(1));
					}
					if(plantBeingDragged.getName()=="Aster"){
						view.queueMove(new DeleteCreatureMove(1));
					}
					if(plantBeingDragged.getName()=="Eastern Red Cedar"){
						view.queueMove(new DeleteCreatureMove(2));
					}
				}
				else if(!whereEnd && endDisplay.getPlant(endIndex) == null){
					state = State.SEEDMENU;
					view.buyMenu();
					this.endIndex=endIndex;
					this.dispEnd = dispEnd;
				}
				else if (plantBeingDragged != null)
					plantBeingDragged.setLoc(oldLoc.getX(), oldLoc.getY());
			}
			else if(customer != null && customer.getDesiredPlant().getDominant() != -1 && !customer.isLeaving())
			{
				boolean whereStart=false;
				int dispStart=-1;

				int i = 0;
				for(Display d:view.getGame().getStore().getFront()){
					if(startDisplay == d){
						whereStart = true;
						dispStart = i;
					}
					i++;	
				}

				i = 0;
				for(Display d:view.getGame().getStore().getBack()){
					if(startDisplay == d){
						whereStart = false;
						dispStart = i;
					}
					i++;	
				}
				if(plantBeingDragged != null){
					view.queueMove(new CustomerBuyRequestMove(whereStart, dispStart, startIndex, customer));
					
					if(plantBeingDragged.getName()=="Common Milkweed"){
						view.queueMove(new DeleteCreatureMove(1));
					}
					if(plantBeingDragged.getName()=="Aster"){
						view.queueMove(new DeleteCreatureMove(1));
					}
					if(plantBeingDragged.getName()=="Eastern Red Cedar"){
						view.queueMove(new DeleteCreatureMove(2));
					}
				}
			}
			else if (plantBeingDragged != null)
			{
				plantBeingDragged.setLoc(oldLoc.getX(), oldLoc.getY());
			}
			plantBeingDragged = null;
			startDisplay = null;
		}
		else{
			state = State.NORMAL;
			view.buyMenuEnd();
			int buyIndex = findSeedInMenu(e.getPoint());
			if(buyIndex==1)
				view.queueMove(new PlantBuyMove(dispEnd, endIndex, new JapaneseBarberry()));
			else if(buyIndex==2)
				view.queueMove(new PlantBuyMove(dispEnd, endIndex, new CommonMilkweed()));
			else if(buyIndex==3)
				view.queueMove(new PlantBuyMove(dispEnd, endIndex, new EnglishIvy()));
			else if(buyIndex==4)
				view.queueMove(new PlantBuyMove(dispEnd, endIndex, new EasternRedCedar()));
			else if(buyIndex==5)
				view.queueMove(new PlantBuyMove(dispEnd, endIndex, new NorwayMaple()));
			else if(buyIndex==6)
				view.queueMove(new PlantBuyMove(dispEnd, endIndex, new SweetPepperbush()));
			else if(buyIndex==7)
				view.queueMove(new PlantBuyMove(dispEnd, endIndex, new BurningBush()));
			else if(buyIndex==8)
				view.queueMove(new PlantBuyMove(dispEnd, endIndex, new Aster()));
			else if(buyIndex==9)
				view.queueMove(new PlantBuyMove(dispEnd, endIndex, new WhiteOak()));
			else 
				System.out.print(buyIndex);
		}

		Point p = e.getPoint();
		//Clicked the save button
		if((p.x >= 1348*View.xscale && p.x <= (1348+200)*View.xscale) && (p.y >= 75*View.yscale && p.y <= (75+50)*View.yscale)){
			JFileChooser fileDialog = new JFileChooser();
			fileDialog.addChoosableFileFilter(new FileFilter(){
				@Override
				public boolean accept(File f) {
					if(f.isDirectory())
						return true;
					String ext = f.getName().split("\\.")[f.getName().split("\\.").length-1];
					if(ext!=null){
						if(ext.equals("pla"))
							return true;
					}
					return false;
				}

				@Override
				public String getDescription() {
					return "Game Files (.pla)";
				}	
			});
			int result = fileDialog.showSaveDialog(view);
			if(result == JFileChooser.APPROVE_OPTION){
				try{
					File file = fileDialog.getSelectedFile();
					String str = file.getName();
					if(!str.contains("\\.")){
						str = str.concat(".pla");
					}
					String[] fileName = str.split("\\.");
					if(!fileName[fileName.length-1].equalsIgnoreCase("pla"))
						throw new ImproperFileTypeException();
					FileOutputStream fileOut = new FileOutputStream(file);
					ObjectOutputStream out = new ObjectOutputStream(fileOut);
					out.writeObject(view.getPlayer());
					out.close();
					fileOut.close();
				}
				catch(IOException ex){
					ex.printStackTrace();
					JOptionPane.showMessageDialog(view, "There was an error saving the file, please try again", "Saving Error!", JOptionPane.ERROR_MESSAGE);
				}
				catch(ImproperFileTypeException ex){
					ex.printStackTrace();
					JOptionPane.showMessageDialog(view, "The file you chose is not of the correct type, please try again", "File Type Error!", JOptionPane.ERROR_MESSAGE);
				}
			}
		}
	}
	

	@Override
	public void mouseDragged(MouseEvent arg0) {
		Point p = arg0.getPoint();
		if(plantBeingDragged != null)
			plantBeingDragged.setLoc(p.x-50, p.y-50);
		view.repaint();
	}

	@Override
	public void mouseMoved(MouseEvent arg0) {
		// I don't think we want anything  to happen in this method
	}

	public static Display findPlot(Point p1){
		Location p = new Location(p1.x,p1.y); //Why do this when we can just use points?
		Display result = null;
		//Get the list of the displays in the shop
		Game currentGame = view.getGame();
		Store store = currentGame.getStore();

		List<Display> displays = new ArrayList<Display>();
		displays.addAll(store.getFront());
		displays.addAll(store.getBack()); //This is what we want.


		//Find which one has p in it

		for(Display d: displays)
		{
			Location tl = d.getTopLeft();
			Location br = d.getBottomRight();

			if ((p.getX() >= tl.getX()) && (p.getY() >= tl.getY())){
				if ((p.getX() <= br.getX()) && (p.getY() <= br.getY())){
					result = d;
				}
			}
		}
		return result;
	}
	
	public static boolean trash(Point p){
		return (view.getTrashX()<= p.x && p.x <=view.getTrashX()+75*view.xscale &&view.getTrashY()<= p.y && p.y <=view.getTrashY()+86*view.yscale);
	}
	
	public static int findSeedInMenu(Point p){
		if(view.getmenuY()+(26*View.yscale) <= p.y && p.y <= view.getmenuY()+(126*View.yscale)){
			if(view.getmenuX()+(101*View.xscale) <= p.x && p.x <= view.getmenuX()+(201*View.yscale))
				return 1;
			if(view.getmenuX()+(343*View.xscale) <= p.x && p.x <= view.getmenuX()+(443*View.xscale))
				return 2;
			if(view.getmenuX()+(585*View.xscale) <= p.x && p.x <= view.getmenuX()+(685*View.xscale))
				return 3;
		}
		else if(view.getmenuY()+(177*View.yscale) <= p.y && p.y <= view.getmenuY()+(277*View.yscale)){
			if(view.getmenuX()+(101*View.xscale) <= p.x && p.x <= view.getmenuX()+(201*View.yscale))
				return 4;
			if(view.getmenuX()+(343*View.xscale) <= p.x && p.x <= view.getmenuX()+(443*View.xscale))
				return 5;
			if(view.getmenuX()+(585*View.xscale) <= p.x && p.x <= view.getmenuX()+(685*View.xscale))
				return 6;
		}	
		else if(view.getmenuY()+(328*View.yscale) <= p.y && p.y< view.getmenuY()+(428*View.yscale)){
			if(view.getmenuX()+(101*View.xscale) <= p.x && p.x <= view.getmenuX()+(201*View.yscale))
				return 7;
			if(view.getmenuX()+(343*View.xscale) <= p.x && p.x <= view.getmenuX()+(443*View.xscale))
				return 8;
			if(view.getmenuX()+(585*View.xscale) <= p.x && p.x <= view.getmenuX()+(685*View.xscale))
				return 9;
		}	
		return 0;
	}

	/**
	 * 
	 * @param p
	 * @return index for the specific plot where the user is pressing in a given display
	 */
	public static int findLocationInPlot(Point p1){
		/*
		 * Plots will be laid out in the following indexing pattern for this code:
		 * 
		 * [0 , 1 , ... , n]
		 * [n, n+1, ... ,2*n]
		 * [..., ..., ..., ....]
		 * [(m-1)*n, (m-1)*n + , ... m*n]
		 * 
		 * But there must be a rectangular arrangement otherwise code will break
		 */
		Display d = findPlot(p1);
		if(d != null){
			Location p = new Location(p1.x,p1.y); //Just use points.
			int stepSizeX = (d.getTopLeft().getX() - d.getBottomRight().getX())/d.getColumns();
			int stepSizeY = (d.getBottomRight().getY() - d.getTopLeft().getY())/d.getRows();
			int cols = d.getColumns();
			if (p.getX() == d.getBottomRight().getX() && p.getY() == d.getBottomRight().getY())
				return ( (d.getTopLeft().getX() - p.getX()) / stepSizeX) + (cols * ( ( (p.getY() - d.getTopLeft().getY()) / stepSizeY) ) ) - 3;
			if (p.getX() == d.getBottomRight().getX())
				return ( (d.getTopLeft().getX() - p.getX()) / stepSizeX) + (cols * ( ( (p.getY() - d.getTopLeft().getY()) / stepSizeY) ) ) - 1;
			if (p.getY() == d.getBottomRight().getY())
				return ( (d.getTopLeft().getX() - p.getX()) / stepSizeX) + (cols * ( ( (p.getY() - d.getTopLeft().getY()) / stepSizeY) ) ) - 2;
			return ( (d.getTopLeft().getX() - p.getX()) / stepSizeX) + (cols * ( ( (p.getY() - d.getTopLeft().getY()) / stepSizeY) ) );
		}
		return -1; //Not in a display
	}
	
	public static Customer findCustomer(Point p1)
	{
		for(Customer c : view.getGame().getStore().getCustomers())
		{
			if(p1.x <= c.getLoc().getX() + Customer.CUST_WIDTH && p1.x >= c.getLoc().getX())
				if(p1.y <= c.getLoc().getY() + Customer.CUST_HEIGHT && p1.y >= c.getLoc().getY() - 100)
					return c;
		}
		return null;
	}

}

